master 拉起分支a、b、c
b更改代码合并入a
c更改代码合并入a
c在代码区域1更改代码合并入a
b不改区域1代码 再次合并入a
区域1代码使用哪个分支的?
1. 初始状态
假设你的操作顺序如下:
-
从 master 拉出分支 a、b、c。
-
b 修改某个文件中的区域1代码,然后合并到 a(此时区域1代码变为 b 的版本)。
-
c 修改同一文件的区域1代码(可能不同内容),然后合并到 a(这时如果区域1和 b 修改的是相同位置,会产生冲突)。
-
接着 b 再次合并到 a。
2. 关键:合并冲突解决记录
3. 步骤 4:b 再次合并到 a
-
这时 b 分支的该区域代码仍然是它自己第一次修改的那个版本(b 的版本)。
-
a 分支已经是 c 的版本。
-
如果 b 从第一次合并到 master 之后,没有再改动区域1,那么 b 和 a 的共同祖先是它们上一次合并时的状态吗?
其实这里要清楚:a 已经包含了 b 的第一个提交和 c 的提交。
再次合并 b 到 a 时,Git 会比较:
-
合并时,Git 会看到:
-
祖先中:区域1 = b 版本
-
a 中:区域1 = c 版本
-
b 中:区域1 = b 版本
-
这意味着从祖先到 a,区域1被改成了 c 的版本;从祖先到 b,区域1没变(还是 b 版本)。
这种情况下,Git 会直接采用 a 的版本,因为 b 相对祖先没有新的改动(b 的版本相对于祖先是相同内容),所以不会有冲突,也不会改变 a 的内容。
4. 结论
最终 a 分支的区域1代码仍然是 c 的版本,而不是 b 的版本,因为在第二次合并 b 时,b 在这个区域相对共同祖先没有新改动,所以不会覆盖 a 中已经更新的内容。
5. 如果 b 在第一次合并后又在区域1改了代码呢?
如果 b 在第一次合并到 a 之后,自己又提交了区域1的新修改,那么第二次合并 b 到 a 时,会触发冲突:
-
祖先(第一次合并时的 b 版本)
-
a 的当前(c 版本)
-
b 的当前(b 的新版本)
这时你需要解决冲突选择保留 a 还是 b 的版本。但根据你的描述,你没有提到 b 在第一次合并后又改了区域1,所以默认 b 没改,因此最终是 c 的版本。
git 共同祖先点的确定
共同祖先是两个分支最近的共同提交节点(分叉点之前最近的共同祖先)。
假设有分支 A 和 B:
|
|
A0 ← B0 (共同祖先) ↖ ↙ M0 (第一次合并提交) ↙ ↘ A1 B1 |
第一次合并后:
-
合并提交 M0 包含 A 和 B 的所有更改
-
但下次合并的共同祖先不是 M0
用之前的例子说明
|
|
初始:M0 (master) ↓ a0 ← b0 ← c0 (都从M0分出,共同祖先是M0) ↓ ↓ ↓ ↓ b1 c1 ↓ ↓ ↓ a1 ←─┘ ↓ (第一次合并b→a) ↓ ↓ a2 ←──────┘ (合并c→a,冲突解决选C) ↓ a3 ←─┐ (再次合并b→a) b1 |
关键分析:第三次合并的共同祖先
|
|
当 a3 合并 b1 时: - a3 的历史:a0 ← b1 ← c1 ← a2 ← a3 - b1 的历史:a0 ← b1 找共同祖先: 1. 从 a3 向上找:a3 ← a2 ← c1 ← b1 ← a0 2. 从 b1 向上找:b1 ← a0 3. 最近的共同提交是:b1 (不是a1,也不是a0) 所以第三次合并的共同祖先是 b1! |
为什么是 b1 而不是 a1?
因为:
-
b1 是 b 分支的最新提交
-
a3 包含了 b1(通过第一次合并)
-
它们最后共同拥有的提交就是 b1
Git 查找共同祖先的算法
Git 使用 三路合并(three-way merge)
总结规则(细节过于复杂,暂不考虑)
-
共同祖先不一定是合并提交节点
-
共同祖先是两个分支最后共享的提交
-
如果A分支包含了B分支的提交,那么这些提交就是共同祖先的一部分
-
Git会找到最近的共同祖先,而不是随便选一个
直接使用命令确认两个分支的共同祖先:
|
|
# Git 会找到两个分支的最近共同祖先 git merge-base branch-a branch-b |
|
|
# 显示提交备注 git log -1 $(git merge-base branch-a branch-b) --oneline |
「三年博客,如果觉得我的文章对您有用,请帮助本站成长」
共有 0 - git 三路合并范例